/* 抽象工厂 */

/// 建造汽车的抽象工厂
pub trait AbstractVehicleFactory {
    /// 建造发动机
    fn create_engine(&self) -> Box<dyn Engine>;

    /// 建造车架
    fn create_frame(&self) -> Box<dyn Frame>;
}

/// 发动机
pub trait Engine {
    fn name(&self) -> String;
}

/// 车架
pub trait Frame {
    fn name(&self) -> String;
}

/// 车辆
pub struct Vehicle {
    engine: Box<dyn Engine>,
    frame: Box<dyn Frame>
}

impl Vehicle {
    pub fn show(&self) -> String {
        format!("这是一辆由 {} 和 {} 组装成的汽车", self.frame.name(), self.engine.name())
    }
}

/// 奔驰系列产品
mod benz {
    use super::*;

    pub struct BenzFactory {}
    
    impl AbstractVehicleFactory for BenzFactory {

        fn create_engine(&self) -> Box<dyn Engine> {
            Box::new(BenzEngine{})
        }
        
        fn create_frame(&self) -> Box<dyn Frame> {
            Box::new(BenzFrame{})
        }
    }

    struct BenzEngine {}

    impl Engine for BenzEngine {
        fn name(&self) -> String {
            String::from("奔驰M270发动机")
        }
    }

    struct BenzFrame {}

    impl Frame for BenzFrame {
        fn name(&self) -> String {
            String::from("奔驰MDB车架")
        }
    }
}

/// 宝马系列产品
mod bmw {
    use super::*;

    pub struct BmwFactory {}

    impl AbstractVehicleFactory for BmwFactory {

        fn create_engine(&self) -> Box<dyn Engine> {
            Box::new(BmwEngine{})
        }

        fn create_frame(&self) -> Box<dyn Frame> {
            Box::new(BmwFrame{})
        }
    }

    struct BmwEngine {}

    impl Engine for BmwEngine {
        fn name(&self) -> String {
            String::from("宝马N20发动机")
        }
    }

    struct BmwFrame {}

    impl Frame for BmwFrame {
        fn name(&self) -> String {
            String::from("宝马315车架")
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_abstract_factory_1() {
        let factory = benz::BenzFactory{};
        let engine = factory.create_engine();
        let frame = factory.create_frame();
        let vehicle = Vehicle {
            engine: engine,
            frame: frame
        };
        assert_eq!("这是一辆由 奔驰MDB车架 和 奔驰M270发动机 组装成的汽车", vehicle.show());
    }

    #[test]
    fn test_abstract_factory_2() {
        let factory = bmw::BmwFactory{};
        let engine = factory.create_engine();
        let frame = factory.create_frame();
        let vehicle = Vehicle {
            engine: engine,
            frame: frame
        };
        assert_eq!("这是一辆由 宝马315车架 和 宝马N20发动机 组装成的汽车", vehicle.show());
    }
}